package pers.cz.testNg;

import pers.cz.cache.BaseDataCache;
import pers.cz.json.JsonUtil;
import pers.cz.mapper.TestCaseMapper;
import pers.cz.message.MessageType;
import pers.cz.message.MessageUtil;
import pers.cz.model.TestCase;
import pers.cz.model.TestCaseParams;
import pers.cz.queue.RequestQueue;
import pers.cz.regularexpression.ExpressionUtils;
import pers.cz.http.HttpUtils;
import pers.cz.spring.SpringContextUtil;
import pers.cz.websocket.MessagePushSocketUtils;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.Reporter;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.IOException;
import java.util.*;

/**
 * @program: PostGirl-panent
 * @description: TestNg
 * @author: Cheng Zhi
 * @create: 2021-07-23 13:49
 **/
public class TestNg {

    Logger logger= LoggerFactory.getLogger(TestNg.class);

    TestCaseMapper testCaseMapper;

    /**
     * 初始化测试用例的入参
     * @return
     */
    @DataProvider(name = "Data")
    public Object[][] init() {

        testCaseMapper = (TestCaseMapper) SpringContextUtil.getBean("testCaseMapper");
        String idsAndAddress = (String) RequestQueue.getHeadQueue();
        String address = "";
        String[] split = idsAndAddress.split("\\^");
        address = split[1];
        List<Integer> idsIntger = new ArrayList<>();
        String idsString = split[0];
        String userId = split[2];
        String[] split1 = idsString.split(",");
        for (String ids : split1) {
            idsIntger.add(Integer.valueOf(ids));
        }
        if (RequestQueue.deleteHeadQueue() && logger.isDebugEnabled()) {
            logger.debug("删除队首成功");
        }
        List<TestCase> listCases = testCaseMapper.queryAllTestCaseIds(idsIntger);
        Object[][] objects = new Object[listCases.size()][];
        for (int i=0; i<listCases.size(); i++) {
            Object[] o = new Object[7];
            o[0] = listCases.get(i).getRequest();
            o[1] = listCases.get(i).getExpectedResponse();
            o[2] = address;
            o[3] = String.valueOf(listCases.get(i).getId());
            o[4] = listCases.get(i).getIgnoreFields();
            o[5] = listCases.get(i).getCaseName(); // 该字段用于报告展示
            o[6] = userId;
            objects[i] = o;
        }
        return objects;
    }

    /**
     * 测试用例
     */
    @Test(dataProvider = "Data")
    public void testCase(String request, String response, String url, String id, String ignoreFields, String caseName, String userId) {
        String isPass = "0";

        // 替换请求中的参数
        request = replaceParam(request);
        // 发送请求
        Map<String, String> header = new HashMap<String, String>();
        header.put("caseId", id);
        header.put("type", "PLAYBACK"); // 回放标识，需要配合
        String result = HttpUtils.post(request, url, header);
        Reporter.log("实际出参：" + result);
        // 将出参入库

        JsonElement jsonResponse = new JsonParser().parse(response);
        JsonElement jsonresult = new JsonParser().parse(result);
        Map<String,String> map = new HashMap();
        if (ignoreFields != null && !"".equals(ignoreFields)) {
            String[] fields = ignoreFields.split(",");
            Arrays.asList(fields);
            for (int i=0; i<fields.length; i++) {
                map.put(fields[i], "ignore");
            }
        }

        String newResponse = JsonUtil.replaceJsonNode(jsonResponse, map).toString();
        String newResult = JsonUtil.replaceJsonNode(jsonresult, map).toString();
        String content = "";
        try {
            Assert.assertEquals(newResponse,newResult);
            content = "notify|执行成功,请刷新后再下载报告";
        } catch (AssertionError error) {
            isPass = error.getMessage();
            content = "notify|执行失败，请刷新后再下载报告查看具体原因";
            // 此处要重新抛出异常，要不然报告永远是pass
            throw new AssertionError(error);
        } finally {
            updateTestCase(result, id, isPass);
            MessageUtil.insertNotifyMessage(content, MessageType.getName("notify"), "未读", userId);
            // 发送实时消息
            MessagePushSocketUtils.sendInfo(content,Integer.valueOf(userId));
        }

    }

    /**
     * 将真实的请求响应插入数据库
     * @param result
     * @param id
     */
    public void updateTestCase(String result, String id, String isPass) {

        TestCase testCase = new TestCase();
        testCase.setResultResponse(result);
        testCase.setId(Integer.valueOf(id));
        testCase.setResult(isPass);
        // 如果对比结果中包含错误信息，则结果标识记为1.
        if (isPass != "0") {
            testCase.setResultType(1);
        } else {
            testCase.setResultType(0);
        }
        testCaseMapper.updateByPrimaryKeySelective(testCase);
    }

    /**
     * 获取案例参数
     * @return
     */
    private Map<String, String> getParamNames() {

        // 查询缓存
        List<TestCaseParams> allTestCaseParams = SpringContextUtil.getBean(BaseDataCache.class).getAllTestCaseParams();
        Map<String, String> map = new HashMap<>();
        for (TestCaseParams testCaseParams : allTestCaseParams) {
            if (testCaseParams.getGenerate().equals("1")) {
                // 表示生成表达式：
                try {
                    String value = ExpressionUtils.random(testCaseParams.getGenerateRule());
                    logger.debug("表达式生成结果：" + value);
                    map.put(testCaseParams.getParamName(), value);
                } catch (Exception e) {
                    logger.error(testCaseParams.getParamName() + "生成表达式出错：",e);
                }
            } else {
                map.put(testCaseParams.getParamName(), testCaseParams.getParamValue());
            }

        }

        return map;
    }
    /**
     * 替换模板中的参数
     * @param jsonTemplate
     * @return
     */
    private String replaceParam(String jsonTemplate) {


        if (!jsonTemplate.contains("$")) {
            return jsonTemplate;
        }
        Map<String, String> paramNames = getParamNames();
        for (String paramName : paramNames.keySet()) {

            jsonTemplate = jsonTemplate.replaceAll("\\$\\{".concat(paramName).concat("\\}"),paramNames.get(paramName));
        }

        return jsonTemplate;
    }

}
